#pragma once
#include "Perceptron.h"

template<typename LOSS, typename REGULARIZER>
class RegularizedPerceptron : public Perceptron
{
protected:
  double m_C;
  RegularizedPerceptron() {}
public:
  RegularizedPerceptron(double rate, double C)
    : Perceptron(rate), m_C(C)
  {
  }

  virtual ~RegularizedPerceptron(void)
  {
  }

  // subgradient descent method
  virtual double Learn(const Example& example, int iter)
  {
    const arma::sp_mat& x = example.GetInput();
    CheckDimension(x);

    double predict_label = Predict(x);

    arma::sp_mat lossWeightGrad, regWeightGrad;
    double lossBiasGrad, regBiasGrad;

    LOSS loss(example);
    REGULARIZER regularizer;

    loss.grad(m_Weight, m_Bias, lossWeightGrad, lossBiasGrad);
    regularizer.grad(m_Weight, m_Bias, regWeightGrad, regBiasGrad);

    double rate = m_Rate / sqrt(iter+1 <= 0 ? 1 : iter+1); // make sure non zero denominator
    m_Weight -= rate*(m_C*lossWeightGrad+regWeightGrad);
    m_Bias -= rate*(m_C*lossBiasGrad+regBiasGrad);

    // TODO Learning here
    return predict_label;	
  }
};

